package main

import (
	"fmt"
	"os"
	"os/signal"
	"pmservice/config"
	"pmservice/db"
	"pmservice/dbfactory"
	"pmservice/graph"
	"pmservice/logger"
	"pmservice/service"
	"runtime"
	"syscall"
	"time"

	_ "net/http/pprof"

	"github.com/99designs/gqlgen/graphql/handler"
	"github.com/99designs/gqlgen/graphql/handler/transport"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

var GqlHandler *handler.Server

func main() {
	go func() {
		config.Init("config.yml")
		r := gin.New()
		r.Use(corsAllow(), ginLogger(), gin.Recovery())
		createGraphqlHandler()
		r.POST("/graphql", GraphqlHandler)
		err := r.Run(config.GetServerAddr())
		if err != nil {
			logger.Errorf("server run failed: %s", err.Error())
			return
		}
	}()

	go func() {
		for {
			logger.Info("goroutines:", runtime.NumGoroutine())
			fmt.Println(logger.Buf())
			time.Sleep(time.Duration(time.Second * 5))
		}
	}()

	// 监听ctrl+c信号
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT)
	<-c
}

func createGraphqlHandler() {
	orm := dbfactory.Factory()
	if config.Cfg.Gorm.AutoMigrate {
		orm.DB.AutoMigrate(
			&db.Admin{},
			&db.Doctor{},
			&db.Ecm{},
			&db.Fac{},
			&db.Hospital{},
			&db.Poc{},
			&db.Settings{},
			&db.Token{},
		)
	}

	GqlHandler = handler.New(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{
		TokenService: service.CreateTokenService(orm),
		Service:      service.NewService(orm),
	}}))
	// h.AddTransport(transport.SSE{})
	// h.AddTransport(transport.Websocket{
	// 	KeepAlivePingInterval: 10 * time.Second,
	// 	Upgrader: websocket.Upgrader{
	// 		CheckOrigin: func(r *http.Request) bool {
	// 			return true
	// 		},
	// 	},
	// })
	GqlHandler.AddTransport(transport.POST{})
	GqlHandler.AddTransport(transport.MultipartForm{})

	// // 开发环境开放文档
	// if config.Cfg.Environment == "dev" {
	// 	GqlHandler.Use(extension.Introspection{})
	// }

	//生产环境下拦截文档请求
	//h.AroundOperations(func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
	//	o := graphql.GetOperationContext(ctx)
	//	if o.OperationName == "IntrospectionQuery" && Environment == "production" {
	//		return func(ctx context.Context) *graphql.Response {
	//			return graphql.ErrorResponse(ctx, "The interface document was denied")
	//		}
	//	}
	//
	//	// 否则，继续处理请求
	//	return next(ctx)
	//})
}

// GraphqlHandler Defining the Graphql handler
func GraphqlHandler(c *gin.Context) {

	GqlHandler.ServeHTTP(c.Writer, c.Request)
}

func corsAllow() gin.HandlerFunc {
	return cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"*"},
		AllowHeaders:     []string{"*"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	})
}

func ginLogger() gin.HandlerFunc {
	return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
		var statusColor, methodColor, resetColor string
		if param.IsOutputColor() {
			statusColor = param.StatusCodeColor()
			methodColor = param.MethodColor()
			resetColor = param.ResetColor()
		}

		if param.Latency > time.Minute {
			param.Latency = param.Latency.Truncate(time.Second)
		}

		return fmt.Sprintf("GIN [%v] |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
			param.TimeStamp.Format("2006/01/02-15:04:05"),
			statusColor, param.StatusCode, resetColor,
			param.Latency,
			param.ClientIP,
			methodColor, param.Method, resetColor,
			param.Path,
			param.ErrorMessage,
		)
	})
}
